﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
using System.IO;
using System.Runtime.InteropServices;
using System.Net.Security;
using System.Diagnostics;
using System.Threading;
//using ssl;
using System.Net;

namespace Sim
{
    class LoadApp
    {
        static public void Select(string path)
        {
            if (!File.Exists(path))
            {
                return;
            }
            AppPath = path;

            return;
        }
        static public void Unload()
        {
            Program.SslApp?.Stop();
            Program.SslApp = null;
            return;
        }

        static public void Run()
        {
            ssl.SslProcess.SslDbgInfo = SslDbgInfo;
            if (Program.SslApp == null)
            {
                Program.SslApp = new SslApp();
                Program.SslApp.Start();
                return;
            }
            return;
        }

        private static string AppPath;
        

        private static void SslDbgInfo(string Msg)
        {
            Action action = () => { SptInfo.AppendText(Msg); };
            SptInfo.BeginInvoke(action);

        }
        public static System.Windows.Forms.TextBox SptInfo;
        public static Assembly AssemblyResolve(object sender, ResolveEventArgs args)
        {
            var assName = new AssemblyName(args.Name).FullName;
            try
            {
                var da = Assembly.LoadFrom(AppPath);

                return da;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
                throw new DllNotFoundException(assName);//否则抛出加载失败的异常
            }
        }

    }
#if false
    class LoadApp:MarshalByRefObject
    {
        static public void Select(string path)
        {
            if (!File.Exists(path))
            {
                return;
            }

            appPath = path;

        }
        static public void Unload()
        {
            Program.SslApp?.Stop();
            if (ad != null)
            {
                AppDomain.Unload(ad);
            }
            ad = null;
            assembly = null;
        }
        static public void Run()
        {
            Load();
        }
        static private void  Load()
        {
            if (appPath == null)
            {
                return;
            }
            if (!File.Exists(appPath))
            {
                return;
            }
            if (ad != null)
            {
                Unload();
            }

            ad = AppDomain.CreateDomain("SslProcess");
            String name = Assembly.GetExecutingAssembly().GetName().FullName;
            loadapp = (LoadApp)ad.CreateInstanceAndUnwrap(name, typeof(LoadApp).FullName);

            assembly = Assembly.LoadFile(appPath);

            if (Program.SslApp!=null)
            {
                Program.SslApp.Stop();
                Program.SslApp = null;
            }

            Program.SslApp = new SslApp();

            Program.SslApp.sslMain = (SslApp.SslCallBack)Invoke("SslMain",typeof(SslApp.SslCallBack));
            Program.SslApp.SslSampCntPerCircle = (SslApp.SslCallBack)Invoke("SslSampCntPerCircle", typeof(SslApp.SslCallBack));
            Program.SslApp.Ssl1MsInt = (SslApp.SslVoidCallBack)Invoke("Ssl1MsInt", typeof(SslApp.SslVoidCallBack));
            Program.SslApp.SslSampInt = (SslApp.SslVoidCallBack)Invoke("SslSampInt", typeof(SslApp.SslVoidCallBack));
            Program.SslApp.SslBoardData = (SslApp.SslBoardDataCallBack)Invoke("BoardData", typeof(SslApp.SslBoardDataCallBack));
            Program.SslApp.SslBoardDataInfo = (SslApp.SslBoardDataInfoCallBack)Invoke("BoardDataInfo", typeof(SslApp.SslBoardDataInfoCallBack));

            Program.SslApp.Start();

        } 
        static private Delegate Invoke(string methodName,Type delegatemethod)
        {
            Type tp = assembly.GetType("ssl.SslProcess");

            MethodInfo mi = tp.GetMethod(methodName);
            return mi.CreateDelegate(delegatemethod);
        }


        private static string appPath;
        private static Assembly assembly;
        private static AppDomain ad;
        private static LoadApp loadapp;
    }
#endif

#if false
    class LoadApp
    {
        static public void Select(string path)
        {
            if (!File.Exists(path))
            {
                return ;
            }


            AppPath = path;

            return;
        }
        static public void Unload()
        {
            

            return ;
        }

        static public void Run()
        {
            if (AppPath == null)
            {
                return ;
            }

            if (Program.SslApp == null)
            {
                Program.SslApp = new SslApp();
                Program.SslApp.Start();
                return ;
            }
            return ;
        }



        private static string AppPath;

        public static Assembly AssemblyResolve(object sender, ResolveEventArgs args)
        {
            var assName = new AssemblyName(args.Name).FullName;
            try
            {
                var da = Assembly.LoadFrom(AppPath);

                return da;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
                throw new DllNotFoundException(assName);//否则抛出加载失败的异常
            }
        }

    }
#endif
#if false
    class LoadApp
    {
        public int Select(string path)
        {
            if (!File.Exists(path))
            {
                return -1;
            }

            AppPath = path;

            return 0;
        }
        public int Unload()
        {
            AppDll = null;

            Program.App?.Stop();

            Program.App = null;

            return 0;
        }

        public int Run()
        {
            if (!File.Exists(AppPath))
            {
                return -1;
            }
            AppDll = Assembly.LoadFile(AppPath);

            if (null== Program.App)
            {
                Program.App = new SptApp();
            }

            Type sslprocess = AppDll.GetType("spt.SslProcess");

            MethodInfo sslmain = sslprocess.GetMethod("SslSampInt");
            Program.App.IntSamp = (SptApp.AppHandle) sslmain.CreateDelegate(typeof(SptApp.AppHandle));

            sslmain = sslprocess.GetMethod("SslMain");
            Program.App.SslMain = (SptApp.AppHandle)sslmain.CreateDelegate(typeof(SptApp.AppHandle));

            Program.App.Start();

            return 0;
        }

        

        private string AppPath;

        Assembly AppDll;



#endif
#if false
    class LoadApp
    {
        [DllImport("App.dll")]
        private static extern int SptMain();
        public int Load(string path)
        {
            var result = SptMain();
            return 0;
        }
    }
#endif
#if false
    class LoadApp
    {

        /// <summary>
        /// DLLWrapper
        /// </summary>
        internal class DLLWrapper
        {
            [DllImport("kernel32.dll")]
            private static extern uint GetLastError();


            /// <summary>
            /// API LoadLibraryEx
            /// </summary>
            /// <param name="lpFileName"></param>
            /// <param name="hReservedNull"></param>
            /// <param name="dwFlags"></param>
            /// <returns></returns>
            [DllImport("kernel32.dll", EntryPoint = "LoadLibraryEx", SetLastError = true)]
            private static extern int LoadLibraryEx(string lpFileName, IntPtr hReservedNull, LoadLibraryFlags dwFlags);

            /// <summary>
            /// API GetProcAddress
            /// </summary>
            /// <param name="handle"></param>
            /// <param name="funcname"></param>
            /// <returns></returns>
            [DllImport("Kernel32", EntryPoint = "GetProcAddress", SetLastError = true)]
            public static extern int GetProcAddress(int handle, string funcname);

            /// <summary>
            ///  API FreeLibrary
            /// </summary>
            /// <param name="handle"></param>
            /// <returns></returns>
            [DllImport("Kernel32", EntryPoint = "FreeLibrary", SetLastError = true)]
            private static extern int FreeLibrary(int handle);

            ///<summary>
            /// 通过非托管函数名转换为对应的委托 , by jingzhongrong
            ///</summary>
            ///<param name="dllModule"> 通过 LoadLibrary 获得的 DLL 句柄 </param>
            ///<param name="functionName"> 非托管函数名 </param>
            ///<param name="t"> 对应的委托类型 </param>
            ///<returns> 委托实例，可强制转换为适当的委托类型 </returns>
            public static Delegate GetFunctionAddress(int dllModule, string functionName, Type t)
            {
                int address = GetProcAddress(dllModule, functionName);
                if (address == 0)
                    return null;
                else
                    return Marshal.GetDelegateForFunctionPointer(new IntPtr(address), t);
            }

            ///<summary>
            /// 将表示函数地址的 intPtr 实例转换成对应的委托
            ///</summary>
            public static Delegate GetDelegateFromIntPtr(IntPtr address, Type t)
            {
                if (address == IntPtr.Zero)
                    return null;
                else
                    return Marshal.GetDelegateForFunctionPointer(address, t);
            }

            ///<summary>
            /// 将表示函数地址的 int  转换成对应的委托
            ///</summary>
            public static Delegate GetDelegateFromIntPtr(int address, Type t)
            {
                if (address == 0)
                    return null;
                else
                    return Marshal.GetDelegateForFunctionPointer(new IntPtr(address), t);
            }

            /// <summary>
            /// 加载sdk
            /// </summary>
            /// <param name="lpFileName"></param>
            /// <returns></returns>
            public static int LoadSDK(string lpFileName)
            {
                if (File.Exists(lpFileName))
                {
                    var hReservedNull = IntPtr.Zero;
                    var dwFlags = LoadLibraryFlags.LOAD_WITH_ALTERED_SEARCH_PATH;

                    var result = LoadLibraryEx(lpFileName, hReservedNull, dwFlags);

                    var errCode = GetLastError();
                  //  LogHelper.Info($"LoadSDK Result:{result}, ErrorCode: {errCode}");

                    return result;
                }
                return 0;
            }

            /// <summary>
            /// 释放sdk
            /// </summary>
            /// <param name="handle"></param>
            /// <returns></returns>
            public static int ReleaseSDK(int handle)
            {
                try
                {
                    if (handle > 0)
                    {
                       // LogHelper.Info($"FreeLibrary handle：{handle}");
                        var result = FreeLibrary(handle);
                        var errCode = GetLastError();
                       // LogHelper.Info($"FreeLibrary Result:{result}, ErrorCode: {errCode}");
                        return 0;
                    }
                    return -1;
                }
                catch //(Exception ex)
                {
                    //LogHelper.Error(ex);
                    return -1;
                }
            }
        }

        /// <summary>
        /// LoadLibraryFlags
        /// </summary>
        public enum LoadLibraryFlags : uint
        {
            /// <summary>
            /// DONT_RESOLVE_DLL_REFERENCES
            /// </summary>
            DONT_RESOLVE_DLL_REFERENCES = 0x00000001,

            /// <summary>
            /// LOAD_IGNORE_CODE_AUTHZ_LEVEL
            /// </summary>
            LOAD_IGNORE_CODE_AUTHZ_LEVEL = 0x00000010,

            /// <summary>
            /// LOAD_LIBRARY_AS_DATAFILE
            /// </summary>
            LOAD_LIBRARY_AS_DATAFILE = 0x00000002,

            /// <summary>
            /// LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE
            /// </summary>
            LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE = 0x00000040,

            /// <summary>
            /// LOAD_LIBRARY_AS_IMAGE_RESOURCE
            /// </summary>
            LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x00000020,

            /// <summary>
            /// LOAD_LIBRARY_SEARCH_APPLICATION_DIR
            /// </summary>
            LOAD_LIBRARY_SEARCH_APPLICATION_DIR = 0x00000200,

            /// <summary>
            /// LOAD_LIBRARY_SEARCH_DEFAULT_DIRS
            /// </summary>
            LOAD_LIBRARY_SEARCH_DEFAULT_DIRS = 0x00001000,

            /// <summary>
            /// LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR
            /// </summary>
            LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR = 0x00000100,

            /// <summary>
            /// LOAD_LIBRARY_SEARCH_SYSTEM32
            /// </summary>
            LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800,

            /// <summary>
            /// LOAD_LIBRARY_SEARCH_USER_DIRS
            /// </summary>
            LOAD_LIBRARY_SEARCH_USER_DIRS = 0x00000400,

            /// <summary>
            /// LOAD_WITH_ALTERED_SEARCH_PATH
            /// </summary>
            LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008
        }

      //  UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Ansi)]
        public delegate int AppMain();

        public int Load(string path)
        {
            if (!File.Exists(path))
            {
                return -1;
            }
            int result=0;
            //1. 加载sdk
            if (sdkModule!=0)
            {
                Unload();
            }
            sdkModule = DLLWrapper.LoadSDK(path);

            // 2. 通过handle 找到相关的函数
            AppMain appmain = (AppMain)DLLWrapper.GetFunctionAddress(sdkModule, "main", typeof(AppMain));

            result = appmain();




            return 0;
        }
        public int Unload()
        {
            DLLWrapper.ReleaseSDK(sdkModule);
            sdkModule = 0;
            return 0;
        }
        private int sdkModule;       
    }
#endif



}
